﻿/********************************************************************************
** 作者： Mick
** 邮箱： zheng_jinfan@126.com
** 主页： http://www.zhengjinfan.cn
** 创始时间：2016-2-17
** 描述：
**      [辅助类]三重DES加密服务类
*********************************************************************************/
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace BestEasyCMS.Framework.Util
{
    /// <summary>
    /// [辅助类]三重DES加密服务类
    /// </summary>
    public sealed class TripleDesService :IDisposable
    {
        #region 构造实例

        /// <summary>
        /// 私有默认构造函数，禁止用户使用new()创建对象
        /// </summary>
        private TripleDesService()
        {
        }

        /// <summary>
        /// 构建类的实例对象
        /// </summary>
        public static TripleDesService Instance
        {
            get { return new TripleDesService(); }
        }

        #endregion 构造实例
        //private string iv = "#$^%&&*Yisifhsfjsljfslhgosdshf26382837sdfjskhf97(*&(*";
        private readonly string _iv = "#$^%&&*Y"; //8字节
        private readonly string _key;
        private readonly TripleDES _mydes;

        /// <summary>
        /// 对称加密类的构造函数
        /// </summary>
        /// <param name="key"></param>
        public TripleDesService(string key)
        {
            _mydes = new TripleDESCryptoServiceProvider();
            _key = key;
            _mydes.Key = GetLegalKey();
            _mydes.IV = GetLegalIv();
        }

        /// <summary>
        /// 对称加密类的构造函数
        /// </summary>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        public TripleDesService(string key, string iv)
            : this(key)
        {
            _iv = iv;
        }


        /// <summary>
        /// 获得密钥
        /// </summary>
        /// <returns>密钥</returns>
        private byte[] GetLegalKey()
        {
            //mydes.GenerateKey();
            //byte[] bytTemp = mydes.Key;
            //int KeyLength = bytTemp.Length;
            const int keyLength = 24;
            byte[] bs;
            var len = _key.Length;
            if (len == keyLength)
            {
                bs = Encoding.ASCII.GetBytes(_key);
            }
            else if (len > keyLength)
            {
                var temp = _key.Substring(0, keyLength);
                bs = Encoding.ASCII.GetBytes(temp);
            }
            else
            {
                var temp = _key.PadRight(keyLength, ' ');
                bs = Encoding.ASCII.GetBytes(temp);
            }
            if (TripleDES.IsWeakKey(bs))
            {
                throw new CryptographicException(String.Format("指定密钥{0}是TripleDES的已知弱密钥，不能使用。", _key));
            }
            return bs;
        }

        /// <summary>
        /// 获得初始向量IV
        /// </summary>
        /// <returns>初试向量IV</returns>
        private byte[] GetLegalIv()
        {
            //mydes.GenerateIV();
            //byte[] bytTemp = mydes.IV;
            //int IVLength = bytTemp.Length;
            const int ivLength = 8;
            var len = _iv.Length;
            if (len == ivLength)
            {
                return Encoding.ASCII.GetBytes(_iv);
            }

            var sTemp = len > ivLength ? _iv.Substring(0, ivLength) : _iv.PadRight(ivLength, ' ');
            return Encoding.ASCII.GetBytes(sTemp);
        }

        /// <summary>
        /// 加密方法
        /// </summary>
        /// <param name="input">待加密的串</param>
        /// <returns>经过加密的串</returns>
        public string Encrypt(string input)
        {
            if (input.Trim() == "") return "";
            try
            {
                var bytIn = Encoding.UTF8.GetBytes(input);
                var ms = new MemoryStream();
                //mydes.Key = GetLegalKey();
                //mydes.IV = GetLegalIV();
                var encrypto = _mydes.CreateEncryptor();
                var cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
                cs.Write(bytIn, 0, bytIn.Length);
                cs.FlushFinalBlock();
                ms.Close();
                var bytOut = ms.ToArray();
                return Convert.ToBase64String(bytOut);
            }
            catch (CryptographicException ex)
            {
                throw new CryptographicException(String.Format("在文件解密的时候出现错误！key：{0} 待解密的串：{1} 错误提示： {2}\n", _key, input,
                                                               ex.Message));
            }
            catch (Exception ex)
            {
                throw new Exception("在文件加密的时候出现错误！错误提示： \n" + ex.Message);
            }
        }

        /// <summary>
        /// 解密方法
        /// </summary>
        /// <param name="input">待解密的串</param>
        /// <returns>经过解密的串</returns>
        public string Decrypt(string input)
        {
            if (input.Trim() == "") return "";
            try
            {
                var bytIn = Convert.FromBase64String(input);
                var ms = new MemoryStream(bytIn, 0, bytIn.Length);
                var encrypto = _mydes.CreateDecryptor();
                var cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
                var sr = new StreamReader(cs);
                return sr.ReadToEnd();
            }
            catch (CryptographicException ex)
            {
                throw new CryptographicException(String.Format("在文件解密的时候出现错误！key：{0} 待解密的串：{1} 错误提示： {2}\n", _key, input,
                                                               ex.Message));
            }
            catch (Exception ex)
            {
                throw new Exception("在文件解密的时候出现错误！错误提示： \n" + ex.Message);
            }
        }

        /// <summary>
        /// 加密方法byte[] to byte[]
        /// </summary>
        /// <param name="input">待加密的byte数组</param>
        /// <returns>经过加密的byte数组</returns>
        public byte[] Encrypt(byte[] input)
        {
            try
            {
                var bytIn = input;
                var ms = new MemoryStream();
                var encrypto = _mydes.CreateEncryptor();
                var cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
                cs.Write(bytIn, 0, bytIn.Length);
                cs.FlushFinalBlock();
                ms.Close();
                var bytOut = ms.ToArray();
                return bytOut;
            }
            catch (Exception ex)
            {
                throw new Exception("在文件加密的时候出现错误！错误提示： \n" + ex.Message);
            }
        }

        /// <summary>
        /// 解密方法byte[] to byte[]
        /// </summary>
        /// <param name="input">待解密的byte数组</param>
        /// <returns>经过解密的byte数组</returns>
        public byte[] Decrypt(byte[] input)
        {
            try
            {
                var bytIn = input;
                var ms = new MemoryStream(bytIn, 0, bytIn.Length);
                var encrypto = _mydes.CreateDecryptor();
                var cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
                var sr = new StreamReader(cs);
                return Encoding.UTF8.GetBytes(sr.ReadToEnd());
            }
            catch (Exception ex)
            {
                throw new Exception("在文件解密的时候出现错误！错误提示： \n" + ex.Message);
            }
        }

        /// <summary>
        /// 加密方法File to File
        /// </summary>
        /// <param name="inFileName">待加密文件的路径</param>
        /// <param name="outFileName">待加密后文件的输出路径</param>
        public void Encrypt(string inFileName, string outFileName)
        {
            try
            {
                var fin = new FileStream(inFileName, FileMode.Open, FileAccess.Read);
                var fout = new FileStream(outFileName, FileMode.OpenOrCreate, FileAccess.Write);
                fout.SetLength(0);

                var bin = new byte[100];
                long rdlen = 0;
                var totlen = fin.Length;

                var encrypto = _mydes.CreateEncryptor();
                var cs = new CryptoStream(fout, encrypto, CryptoStreamMode.Write);
                while (rdlen < totlen)
                {
                    var len = fin.Read(bin, 0, 100);
                    cs.Write(bin, 0, len);
                    rdlen = rdlen + len;
                }
                cs.Close();
                fin.Close();
            }
            catch (Exception ex)
            {
                throw new Exception("在文件加密的时候出现错误！错误提示： \n" + ex.Message);
            }
        }

        /// <summary>
        /// 解密方法File to File
        /// </summary>
        /// <param name="inFileName">待解密文件的路径</param>
        /// <param name="outFileName">待解密后文件的输出路径</param>
        public void Decrypt(string inFileName, string outFileName)
        {
            try
            {
                var fin = new FileStream(inFileName, FileMode.Open, FileAccess.Read);
                var fout = new FileStream(outFileName, FileMode.OpenOrCreate, FileAccess.Write);
                fout.SetLength(0);

                var bin = new byte[100];
                long rdlen = 0;
                var totlen = fin.Length;
                var encrypto = _mydes.CreateDecryptor();
                var cs = new CryptoStream(fout, encrypto, CryptoStreamMode.Write);
                while (rdlen < totlen)
                {
                    var len = fin.Read(bin, 0, 100);
                    cs.Write(bin, 0, len);
                    rdlen = rdlen + len;
                }
                cs.Close();
                fin.Close();
            }
            catch (Exception ex)
            {
                throw new Exception("在文件解密的时候出现错误！错误提示： \n" + ex.Message);
            }
        }

        public void Dispose()
        {
            _mydes.Dispose();
        }
    }
}